﻿package fpc.containers;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import fpc.AComponent;
import fpc.ALayoutable;
import fpc.layouts.ILayout;
import fpc.styles.IStylized;
import fpc.utils.FramePostponer;
import fpc.layouts.ILayoutable;

class Container< T:ILayout > extends AComponent
{
	var _spanLeft:Int;
	
	var _spanRight:Int;
	
	var _spanTop:Int;
	
	var _spanBottom:Int;
	
	var _containerSprite:Sprite;
	
	public function new(layout:T = null)
	{
		super();
		_containerSprite = new Sprite();
		_sprite.addChild(_containerSprite);
		
		_isArrangeValid = true;
		_spanLeft = _spanRight = _spanTop = _spanBottom = 0;
		if (layout != null)
		{
			this.layout = layout;
		}
	}
	
	var _sprite:Sprite;
	
	override function createBaseObject():DisplayObject
	{
		_sprite = new Sprite();
		return _sprite;
	}
	
	public var layout(getLayout, setLayout):T;
	var _layout:T;
	function getLayout()
	{
		return _layout;
	}
	function setLayout(value)
	{
		if (_layout != null)
		{
			_layout.heraldAddChild.remove(onAddChild);
			_layout.heraldRemoveChild.remove(onRemoveChild);
			_layout.heraldChange.remove(onParametersChange);
			for (component in _layout)
			{
				removeComponent(component);
			}
		}
		_layout = value;
		if (value != null)
		{
			_layout.heraldAddChild.add(onAddChild);
			_layout.heraldRemoveChild.add(onRemoveChild);
			_layout.heraldChange.add(onParametersChange);
			for (component in _layout)
			{
				addComponent(component);
			}
		}
		orderArrange();
		return value;
	}
	
	function orderArrange()
	{
		_isArrangeValid = false;
		FramePostponer.addResize(arrange);
	}
	
	function updateSpans()
	{
		var oldHeight = _height;
		var oldWidth = _width;
			
		_containerSprite.x = _spanLeft;
		_containerSprite.y = _spanTop;
		
		_width = _layout.width + _spanLeft + _spanRight;
		_height = _layout.height + _spanTop + _spanBottom;
		
		var newWidth = _layout.width + _spanLeft + _spanRight;
		var newHeight = _layout.height + _spanTop + _spanBottom;
		
		if (Std.int(newWidth) != Std.int(oldWidth) || Std.int(newHeight) != Std.int(oldHeight))
		{
			heraldResize.dispatch(this);
		}
	}
	
	function arrange()
	{
		/*
		TODO
		
		Убрать подписку-отписку на события изменения размера
		По завершении считать раскладку адекватной
		*/
		
		FramePostponer.remove(arrange);
		
		if (_isArrangeValid)
		{
			return;
		}
		
		if (_layout != null)
		{
			var oldHeight = _height;
			var oldWidth = _width;
			
			_layout.width = _width - _spanLeft - _spanRight;
			_layout.height = _height - _spanTop - _spanBottom;
			_layout.arrange();
			
			var newWidth = _layout.width + _spanLeft + _spanRight;
			var newHeight = _layout.height + _spanTop + _spanBottom;
			
			_width = newWidth;
			_height = newHeight;
			
			_isArrangeValid = true;
			
			if (Std.int(newWidth) != Std.int(oldWidth) || Std.int(newHeight) != Std.int(oldHeight))
			{
				heraldResize.dispatch(this);
			}
		}
		else
		{
			_width = 0;
			_height = 0;
		}
	}
	
	function onAddChild(component:ILayoutable)
	{
		addComponent(component);
		orderArrange();
	}
	
	function onRemoveChild(component:ILayoutable)
	{
		removeComponent(component);
		orderArrange();
	}
	
	inline function addComponent(component:ILayoutable)
	{
		component.addTo(_containerSprite);
		component.parent = this;
	}
	
	inline function removeComponent(component:ILayoutable)
	{
		component.removeFrom(_containerSprite);
		component.parent = null;
	}
	
	function onParametersChange(layout:ILayout)
	{
		orderArrange();
	}
	
	var _isArrangeValid:Bool;
	
	override function getWidth()
	{
		if (!_isArrangeValid)
		{
			arrange();
		}
		return _width;
	}
	
	override function setWidth(value)
	{
		_width = value;
		orderArrange();
		return _width;
	}
	
	override function getHeight()
	{
		if (!_isArrangeValid)
		{
			arrange();
		}
		return _height;
	}
	
	override function setHeight(value)
	{
		_height = value;
		orderArrange();
		return _height;
	}
}